package com.sangmo.fts.training.service;

import com.sangmo.boot.framework.common.session.UserSession;
import com.sangmo.boot.framework.common.utils.JsonUtils;
import com.sangmo.boot.framework.data.filter.PageResult;
import com.sangmo.boot.framework.data.filter.PageSearch;
import com.sangmo.boot.framework.data.filter.ValueFilter;
import com.sangmo.boot.framework.plugin.dataview.crud.service.DelegateViewService;
import com.sangmo.boot.framework.plugin.dataview.crud.service.ViewService;
import com.sangmo.fts.teacher.vo.ExaminationDistributionView;
import com.sangmo.fts.teacher.vo.ScoreDistributionRatioView;
import com.sangmo.fts.teacher.vo.ScoreDistributionView;
import com.sangmo.fts.teacher.model.Examination;
import com.sangmo.fts.training.interfaces.GradeRequest;
import com.sangmo.fts.training.vo.LatestScoreView;
import com.sangmo.fts.training.interfaces.ScoreCreation;
import com.sangmo.fts.training.vo.UserRankView;
import com.sangmo.fts.training.model.Score;
import com.sangmo.fts.training.model.Teammate;
import com.sangmo.fts.training.model.Training;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
public class ScoreService extends DelegateViewService<Score> {

    @Autowired
    private ScoreEntityService scoreEntityService;

    @Autowired
    private TeammateEntityService teammateEntityService;

    @Override
    protected ViewService<Score> getEntityService() {
        return scoreEntityService;
    }

    public Score grade(Long id, GradeRequest req) {
        Score score = this.get(id);
        score.setReportMark(req.getMark());
        score = this.save(score);
        afterGrade(score);
        return score;
    }

    private void afterGrade(Score score) {
        //TODO  计算最终成绩


    }

    public PageResult<Score> searchForStudent(PageSearch ps) {
        ps.getFilters().add(new ValueFilter("userId", ValueFilter.OP_EQ, UserSession.getUserInterface().getId()));
        return super.search(ps);
    }

    public Score createOneIfNotExists(Training training) {
        List<Score> scores = scoreEntityService.findByTrainingId(training.getId());
        if (CollectionUtils.isEmpty(scores)) {
            ScoreCreation creation = new ScoreCreation();
            creation.setTrainingId(training.getId());
            creation.setExaminationId(training.getExaminationId());
            creation.setUserId(training.getCreatedBy());
            Score score = scoreEntityService.create(creation);
            return score;
        }
        return scores.get(0);
    }

    public List<Score> createTeamIfNotExists(Training training) {
        List<Score> scores = scoreEntityService.findByTrainingId(training.getId());
        Set<Long> scoreUserIds = scores.stream().map(Score::getUserId).collect(Collectors.toSet());
        List<Teammate> teammates = teammateEntityService.findByTeamId(training.getTeamId());
        Set<Long> teammateUserIds = teammates.stream().map(Teammate::getUserId).collect(Collectors.toSet());
        for (Long userId : teammateUserIds) {
            if (!scoreUserIds.contains(userId)) {
                ScoreCreation creation = new ScoreCreation();
                creation.setExaminationId(training.getExaminationId());
                creation.setUserId(userId);
                creation.setTrainingId(training.getId());
                Score newScore = scoreEntityService.create(creation);
                scores.add(newScore);
            }
        }
        return scores;
    }

    public List<Score> saveAll(List<Score> scores) {
        return scoreEntityService.saveAll(scores);
    }

    public LatestScoreView latestScore() {
        LatestScoreView scoreResult = new LatestScoreView();
        Long currentUserId = (Long)UserSession.getUserInterface().getId();
        Score indiScore = scoreEntityService.findLatestByUserIdAndMode(currentUserId, Examination.Modes.INDIVIDUAL);
        if (null != indiScore) {
            UserRankView result = scoreEntityService.findRankingByExaminationIdAndUserId(currentUserId, indiScore.getExaminationId());
            scoreResult.setIndividualRanking(result);
        }

        Score teamScore = scoreEntityService.findLatestByUserIdAndMode(currentUserId, Examination.Modes.TEAM);
        if (null != teamScore) {
            UserRankView result = scoreEntityService.findRankingByExaminationIdAndUserId(currentUserId, teamScore.getExaminationId());
            scoreResult.setTeamRanking(result);
        }

        return scoreResult;
    }

    public List<ExaminationDistributionView> distributeByExaminationId(Long examinationId) {
        ScoreDistributionView result  =  scoreEntityService.findDistributionByExaminationId(examinationId);
        System.out.println(JsonUtils.writeValue(result));
        if (result.getTotal() == 0) {
            return null;
        }
        List<ExaminationDistributionView> results = new ArrayList<>();
        BigDecimal countDecimal = new BigDecimal(result.getTotal());
        BigDecimal lessThan60Ratio = new BigDecimal(result.getLessThan60()).divide(countDecimal, 2, BigDecimal.ROUND_HALF_UP);
        ExaminationDistributionView lessThan60Result = new ExaminationDistributionView("<60",result.getLessThan60(), lessThan60Ratio);
        results.add(lessThan60Result);
        BigDecimal between60And70Ratio = new BigDecimal(result.getBetween60And70()).divide(countDecimal, 2, BigDecimal.ROUND_HALF_UP);
        ExaminationDistributionView between60And70Result = new ExaminationDistributionView("60-70",result.getBetween60And70(), between60And70Ratio);
        results.add(between60And70Result);
        BigDecimal between70And80Ratio = new BigDecimal(result.getBetween70And80()).divide(countDecimal, 2, BigDecimal.ROUND_HALF_UP);
        ExaminationDistributionView between70And80Result = new ExaminationDistributionView("70-80",result.getBetween70And80(), between70And80Ratio);
        results.add(between70And80Result);
        BigDecimal between80And90Ratio = new BigDecimal(result.getBetween80And90()).divide(countDecimal, 2, BigDecimal.ROUND_HALF_UP);
        ExaminationDistributionView between80And90Result = new ExaminationDistributionView("80-90",result.getBetween80And90(), between80And90Ratio);
        results.add(between80And90Result);
        BigDecimal greaterThan90Ratio = new BigDecimal(result.getGreaterThan90()).divide(countDecimal,2, BigDecimal.ROUND_HALF_UP);
        ExaminationDistributionView greaterThan90Result = new ExaminationDistributionView(">90",result.getGreaterThan90(), greaterThan90Ratio);
        results.add(greaterThan90Result);

        return results;
    }

}
